﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Windows;
using System.Windows.Data;
using DevExpress.Xpf.Editors;
using Loki.Commands;
using Loki.Utils;

namespace Loki.UI.Wpf
{
    internal class ContentControlAdapter<TControl, TViewModel> : LokiObject
        where TControl : FrameworkElement, IView<TViewModel>
        where TViewModel : IViewModel
    {
        #region Log

        public ILog CommonLog
        {
            get
            {
                return Log;
            }
        }

        #endregion Log

        private HashSet<DependencyObject> _BindedObjects = new HashSet<DependencyObject>();

        private HashSet<Binding> _Bindings = new HashSet<Binding>();

        public ContentControlAdapter(TControl P_Control)
        {
            Control = P_Control;

            Commands = new CommandManager();
            Control.Loaded += ViewWindow_Loaded;
            Control.DataContextChanged += ViewWindow_DataContextChanged;
        }

        public TViewModel ViewModel
        {
            get
            {
                return Control.ViewModel;
            }
        }

        protected CommandManager Commands { get; private set; }

        protected TControl Control { get; private set; }

        public Binding AddBinding(Expression<Func<TViewModel, object>> P_Property, DependencyObject P_Target, DependencyProperty P_Targetproperty)
        {
            string L_Name = ExpressionHelper.GetProperty(P_Property).Name;
            Binding L_Expression = new Binding(L_Name);
            L_Expression.Mode = BindingMode.TwoWay;
            L_Expression.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            if (ViewModel.Validators.ContainsKey(L_Name))
            {
                L_Expression.ValidatesOnDataErrors = true;
                L_Expression.ValidatesOnExceptions = true;
            }

            BindingOperations.SetBinding(P_Target, P_Targetproperty, L_Expression);
            _BindedObjects.Add(P_Target);
            _Bindings.Add(L_Expression);

            return L_Expression;
        }

        public Binding AddValueBinding(Expression<Func<TViewModel, object>> P_Property, BaseEdit P_Control)
        {
            return AddBinding(P_Property, P_Control, BaseEdit.EditValueProperty);
        }

        private void ViewModel_ModalChanged(object P_Sender, PropertyChangedEventArgs e)
        {
            if (ViewModel != null && ViewModel.ModalViewModel != null)
            {
                Type L_ModalType = ViewModel.ModalViewModel.GetType();

                ConfirmViewModel L_ConfirmVM = ViewModel.ModalViewModel as ConfirmViewModel;
                if (L_ConfirmVM != null)
                {
                    L_ConfirmVM.DialogResult = MessageBoxes.Confirm(L_ConfirmVM.Message);
                }

                OpenFileViewModel L_OpenVM = ViewModel.ModalViewModel as OpenFileViewModel;
                if (L_OpenVM != null)
                {
                    var L_FileDialog = new Microsoft.Win32.OpenFileDialog();
                    L_FileDialog.Filter = L_OpenVM.Filter;
                    L_FileDialog.InitialDirectory = L_OpenVM.InitialDirectory;
                    bool L_Result = L_FileDialog.ShowDialog() ?? false;

                    if (L_Result)
                    {
                        L_OpenVM.FileName = L_FileDialog.FileName;
                    }
                    else
                    {
                        L_OpenVM.FileName = null;
                    }

                    L_OpenVM.DialogResult = L_Result;
                }

                SaveFileViewModel L_SaveVM = ViewModel.ModalViewModel as SaveFileViewModel;
                if (L_SaveVM != null)
                {
                    var L_FileDialog = new Microsoft.Win32.SaveFileDialog();
                    L_FileDialog.Filter = L_SaveVM.Filter;
                    L_FileDialog.AddExtension = true;
                    L_FileDialog.DefaultExt = L_SaveVM.DefaultExtension;
                    L_FileDialog.InitialDirectory = L_SaveVM.InitialDirectory;
                    bool L_Result = L_FileDialog.ShowDialog() ?? false;

                    if (L_Result)
                    {
                        L_SaveVM.FileName = L_FileDialog.FileName;
                    }
                    else
                    {
                        L_SaveVM.FileName = null;
                    }

                    L_SaveVM.DialogResult = L_Result;
                }
            }
        }

        private void ViewWindow_DataContextChanged(object P_Sender, DependencyPropertyChangedEventArgs e)
        {
            IViewModel L_NewModel = e.NewValue as IViewModel;
            if (L_NewModel != null)
            {
                Log.InfoFormat("View {0} on {1} vm", Control.GetType(), L_NewModel.GetType());
                this.WatchChange(L_NewModel, v => v.ModalViewModel, c => c.ViewModel_ModalChanged);
                L_NewModel.LoadData();
            }

            IViewModel L_OldModel = e.OldValue as IViewModel;
            if (L_OldModel != null)
            {
                //L_OldModel.DoCleanup();
                ToolKit.Event.UnregisterChanged(L_OldModel, this);
            }
        }

        private void ViewWindow_Loaded(object P_Sender, RoutedEventArgs e)
        {
            if (ViewModel != null)
            {
                ViewModel.StartInteraction();
                Log.InfoFormat("View {0} on {1} interaction started", Control.GetType(), ViewModel.GetType());
            }
        }

        #region Dispose

        ~ContentControlAdapter()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases all resources used by an instance of the <see cref="ContentControlAdapter" />
        /// class.
        /// </summary>
        /// <remarks>
        /// This method calls the virtual <see cref="Dispose(bool)" /> method, passing in
        /// <strong>true</strong>, and then suppresses finalization of the instance.
        /// </remarks>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases the unmanaged resources used by an instance of the
        /// <see cref="ContentControlAdapter" /> class and optionally releases the managed
        /// resources.
        /// </summary>
        /// <param name="P_Disposing"><strong>true</strong> to release both managed and unmanaged
        /// resources; <strong>false</strong> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool P_Disposing)
        {
            if (P_Disposing)
            {
                if (Commands != null)
                {
                    Commands.Dispose();
                }
            }
        }

        #endregion Dispose
    }
}